home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / MoreFiles 1.1.1 / FSpCompat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-22  |  21.3 KB  |  726 lines  |  [TEXT/KAHL]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    FSSpec compatibility functions.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support
  7. **
  8. **    File:        FSpCompat.c
  9. **
  10. **    Copyright © 1992-1994 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #ifndef __FSPCOMPAT__
  23. #include "FSpCompat.h"
  24. #endif
  25.  
  26. /*****************************************************************************/
  27.  
  28. /* local constants */
  29.  
  30. enum {
  31.     gestaltBugFixAttrsTwo                    = 'bugy',
  32.     gestaltFSpExchangeFilesCompatibilityFix    = 26,
  33.     gestaltBugFixAttrsThree                    = 'bugx',
  34.     gestaltFSpCreateScriptSupportFix        = 1
  35. };
  36.  
  37. /*****************************************************************************/
  38.  
  39. /* static prototypes */
  40.  
  41. static    Boolean    FSHasFSSpecCalls(void);
  42.  
  43. static    Boolean    QTHasFSSpecCalls(void);
  44.  
  45. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void);
  46.  
  47. static    Boolean    HasFSpCreateScriptSupportFix(void);
  48.  
  49. static    OSErr    GenerateUniqueName(short volume,
  50.                                    long *startSeed,
  51.                                    long dir1,
  52.                                    long dir2,
  53.                                    StringPtr uniqueName);
  54.  
  55. /*****************************************************************************/
  56.  
  57. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  58.  
  59. static    Boolean    FSHasFSSpecCalls(void)
  60. {
  61.     long            response;
  62.     static Boolean    tested = false;
  63.     static Boolean    result = false;
  64.     
  65.     if (!tested)
  66.     {
  67.         tested = true;
  68.         if (Gestalt(gestaltFSAttr, &response) == noErr)
  69.         {
  70.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  71.         }
  72.     }
  73.     return (result);
  74. }
  75.  
  76. /*****************************************************************************/
  77.  
  78. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  79. /* except for FSpExchangeFiles. */
  80.  
  81. static    Boolean    QTHasFSSpecCalls(void)
  82. {
  83.     long            response;
  84.     static Boolean    tested = false;
  85.     static Boolean    result = false;
  86.     
  87.     if (!tested)
  88.     {
  89.         tested = true;
  90.         result = (Gestalt(gestaltQuickTime, &response) == noErr);
  91.     }
  92.     return (result);
  93. }
  94.  
  95. /*****************************************************************************/
  96.  
  97. /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
  98. /* compatibility code has been fixed in system software. */
  99.  
  100. Boolean    HasFSpExchangeFilesCompatibilityFix(void)
  101. {
  102.     long            response;
  103.     static Boolean    tested = false;
  104.     static Boolean    result = false;
  105.     
  106.     if (!tested)
  107.     {
  108.         tested = true;
  109.         if (Gestalt(gestaltBugFixAttrsTwo, &response) == noErr)
  110.         {
  111.             result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
  112.         }
  113.     }
  114.     return (result);
  115. }
  116.  
  117. /*****************************************************************************/
  118.  
  119. /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
  120. /* FSpCreateResFile have been fixed in system software to correctly set */
  121. /* the scriptCode in the volume's catalog. */
  122.  
  123. Boolean    HasFSpCreateScriptSupportFix(void)
  124. {
  125.     long            response;
  126.     static Boolean    tested = false;
  127.     static Boolean    result = false;
  128.     
  129.     if (!tested)
  130.     {
  131.         if (Gestalt(gestaltBugFixAttrsThree, &response) == noErr)
  132.         {
  133.             result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
  134.         }
  135.     }
  136.     return (result);
  137. }
  138.  
  139. /*****************************************************************************/
  140.  
  141. /*
  142. **    File Manager FSp calls
  143. */
  144.  
  145. /*****************************************************************************/
  146.  
  147. pascal    OSErr    FSMakeFSSpecCompat(short vRefNum,
  148.                                    long dirID,
  149.                                    ConstStr255Param fileName,
  150.                                    FSSpecPtr spec)
  151. {
  152.     Boolean    isDirectory;
  153.     
  154.     /* Let the file system create the FSSpec if it can since it does the job */
  155.     /* much more efficiently than I can. */
  156.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  157.         return (FSMakeFSSpec(vRefNum, dirID, fileName, spec));
  158.     else
  159.         return (GetObjectLocation(vRefNum, dirID, (StringPtr)fileName,
  160.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  161.                                     &isDirectory));
  162. }
  163.  
  164. /*****************************************************************************/
  165.  
  166. pascal    OSErr    FSpOpenDFCompat(const FSSpec *spec,
  167.                                 char permission,
  168.                                 short *refNum)
  169. {
  170.     OSErr            result;
  171.     HParamBlockRec    pb;
  172.  
  173.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  174.         return (FSpOpenDF(spec, permission, refNum));
  175.     else
  176.     {
  177.         pb.ioParam.ioVRefNum = spec->vRefNum;
  178.         pb.fileParam.ioDirID = spec->parID;
  179.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  180.         pb.ioParam.ioVersNum = 0;
  181.         pb.ioParam.ioPermssn = permission;
  182.         pb.ioParam.ioMisc = nil;
  183.         result = PBHOpenSync(&pb);    /* OpenDF not supported by System 6, so use Open */
  184.         *refNum = pb.ioParam.ioRefNum;
  185.         return (result);
  186.     }
  187. }
  188.  
  189. /*****************************************************************************/
  190.  
  191. pascal    OSErr    FSpOpenRFCompat(const FSSpec *spec,
  192.                                 char permission,
  193.                                 short *refNum)
  194. {
  195.     OSErr            result;
  196.     HParamBlockRec    pb;
  197.  
  198.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  199.         return (FSpOpenRF(spec, permission, refNum));
  200.     else
  201.     {
  202.         pb.ioParam.ioVRefNum = spec->vRefNum;
  203.         pb.fileParam.ioDirID = spec->parID;
  204.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  205.         pb.ioParam.ioVersNum = 0;
  206.         pb.ioParam.ioPermssn = permission;
  207.         pb.ioParam.ioMisc = nil;
  208.         result = PBHOpenRFSync(&pb);
  209.         *refNum = pb.ioParam.ioRefNum;
  210.         return (result);
  211.     }
  212. }
  213.  
  214. /*****************************************************************************/
  215.  
  216. pascal    OSErr    FSpCreateCompat(const FSSpec *spec,
  217.                                 OSType creator,
  218.                                 OSType fileType,
  219.                                 ScriptCode scriptTag)
  220. {
  221.     OSErr            result;
  222.     UniversalFMPB    pb;
  223.     
  224.     if ((FSHasFSSpecCalls() || QTHasFSSpecCalls()) && HasFSpCreateScriptSupportFix())
  225.         return (FSpCreate(spec, creator, fileType, scriptTag));
  226.     else
  227.     {
  228.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  229.         pb.hPB.fileParam.ioDirID = spec->parID;
  230.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  231.         pb.hPB.fileParam.ioFVersNum = 0;
  232.         result = PBHCreateSync(&(pb.hPB));
  233.         if (result == noErr)
  234.         {
  235.             /* get info on created item */
  236.             pb.ciPB.hFileInfo.ioFDirIndex = 0;
  237.             result = PBGetCatInfoSync(&(pb.ciPB));
  238.             if (result == noErr)
  239.             {
  240.                 /* Set fdScript in FXInfo */
  241.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  242.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  243.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  244.                 pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  245.                                                             ((char)scriptTag | (char)0x80) :
  246.                                                             (smRoman);
  247.                 /* Set creator/fileType */
  248.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  249.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
  250.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  251.                 pb.ciPB.hFileInfo.ioDirID = spec->parID;
  252.                 result = PBSetCatInfoSync(&(pb.ciPB));
  253.             }
  254.         }
  255.         return (result);
  256.     }
  257. }
  258.  
  259. /*****************************************************************************/
  260.  
  261. pascal    OSErr    FSpDirCreateCompat(const FSSpec *spec,
  262.                                    ScriptCode scriptTag,
  263.                                    long *createdDirID)
  264. {
  265.     OSErr            result;
  266.     UniversalFMPB    pb;
  267.  
  268.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  269.         return (FSpDirCreate(spec, scriptTag, createdDirID));
  270.     else
  271.     {
  272.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  273.         pb.hPB.fileParam.ioDirID = spec->parID;
  274.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  275.         result = PBDirCreateSync(&(pb.hPB));
  276.         *createdDirID = pb.hPB.fileParam.ioDirID;
  277.         if (result == noErr)
  278.         {
  279.             /* get info on created item */
  280.             pb.ciPB.dirInfo.ioFDirIndex = 0;
  281.             pb.ciPB.dirInfo.ioDrDirID = spec->parID;
  282.             result = PBGetCatInfoSync(&(pb.ciPB));
  283.             if (result == noErr)
  284.             {
  285.                 /* Set frScript in DXInfo */
  286.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  287.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  288.                 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
  289.                 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
  290.                                                             ((char)scriptTag | (char)0x80) :
  291.                                                             (smRoman);
  292.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  293.                 pb.ciPB.dirInfo.ioDrDirID = spec->parID;            
  294.                 result = PBSetCatInfoSync(&(pb.ciPB));
  295.             }
  296.         }
  297.         return (result);
  298.     }
  299. }
  300.  
  301. /*****************************************************************************/
  302.  
  303. pascal    OSErr    FSpDeleteCompat(const FSSpec *spec)
  304. {
  305.     HParamBlockRec    pb;
  306.  
  307.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  308.         return (FSpDelete(spec));
  309.     else
  310.     {
  311.         pb.ioParam.ioVRefNum = spec->vRefNum;
  312.         pb.fileParam.ioDirID = spec->parID;
  313.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  314.         pb.ioParam.ioVersNum = 0;
  315.         return (PBHDeleteSync(&pb));
  316.     }
  317. }
  318.  
  319. /*****************************************************************************/
  320.  
  321. pascal    OSErr    FSpGetFInfoCompat(const FSSpec *spec,
  322.                                   FInfo *fndrInfo)
  323. {
  324.     OSErr            result;
  325.     HParamBlockRec    pb;
  326.  
  327.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  328.         return (FSpGetFInfo(spec, fndrInfo));
  329.     else
  330.     {
  331.         pb.fileParam.ioVRefNum = spec->vRefNum;
  332.         pb.fileParam.ioDirID = spec->parID;
  333.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  334.         pb.fileParam.ioFVersNum = 0;
  335.         pb.fileParam.ioFDirIndex = 0;
  336.         result = PBHGetFInfoSync(&pb);
  337.         *fndrInfo = pb.fileParam.ioFlFndrInfo;
  338.         return (result);
  339.     }
  340. }
  341.  
  342. /*****************************************************************************/
  343.  
  344. pascal    OSErr    FSpSetFInfoCompat(const FSSpec *spec,
  345.                                   const FInfo *fndrInfo)
  346. {
  347.     OSErr            result;
  348.     HParamBlockRec    pb;
  349.  
  350.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  351.         return (FSpSetFInfo(spec, fndrInfo));
  352.     else
  353.     {
  354.         pb.fileParam.ioVRefNum = spec->vRefNum;
  355.         pb.fileParam.ioDirID = spec->parID;
  356.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  357.         pb.fileParam.ioFVersNum = 0;
  358.         pb.fileParam.ioFDirIndex = 0;
  359.         result = PBHGetFInfoSync(&pb);
  360.         if (result == noErr)
  361.         {
  362.             pb.fileParam.ioFlFndrInfo = *fndrInfo;
  363.             pb.fileParam.ioDirID = spec->parID;
  364.             result = PBHSetFInfoSync(&pb);
  365.         }
  366.         return (result);
  367.     }
  368. }
  369.  
  370. /*****************************************************************************/
  371.  
  372. pascal    OSErr    FSpSetFLockCompat(const FSSpec *spec)
  373. {
  374.     HParamBlockRec    pb;
  375.  
  376.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  377.         return (FSpSetFLock(spec));
  378.     else
  379.     {
  380.         pb.fileParam.ioVRefNum = spec->vRefNum;
  381.         pb.fileParam.ioDirID = spec->parID;
  382.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  383.         pb.fileParam.ioFVersNum = 0;
  384.         return (PBHSetFLockSync(&pb));
  385.     }
  386. }
  387.  
  388. /*****************************************************************************/
  389.  
  390. pascal    OSErr    FSpRstFLockCompat(const FSSpec *spec)
  391. {
  392.     HParamBlockRec    pb;
  393.  
  394.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  395.         return (FSpRstFLock(spec));
  396.     else
  397.     {
  398.         pb.fileParam.ioVRefNum = spec->vRefNum;
  399.         pb.fileParam.ioDirID = spec->parID;
  400.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  401.         pb.fileParam.ioFVersNum = 0;
  402.         return (PBHRstFLockSync(&pb));
  403.     }
  404. }
  405.  
  406. /*****************************************************************************/
  407.  
  408. pascal    OSErr    FSpRenameCompat(const FSSpec *spec,
  409.                                 ConstStr255Param newName)
  410. {
  411.     HParamBlockRec    pb;
  412.  
  413.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  414.         return (FSpRename(spec, newName));
  415.     else
  416.     {
  417.         pb.ioParam.ioVRefNum = spec->vRefNum;
  418.         pb.fileParam.ioDirID = spec->parID;
  419.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  420.         pb.ioParam.ioVersNum = 0;
  421.         pb.ioParam.ioMisc = (Ptr) newName;
  422.         return (PBHRenameSync(&pb));
  423.     }
  424. }
  425.  
  426. /*****************************************************************************/
  427.  
  428. pascal    OSErr    FSpCatMoveCompat(const FSSpec *source,
  429.                                  const FSSpec *dest)
  430. {
  431.     CMovePBRec    pb;
  432.  
  433.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  434.         return (FSpCatMove(source, dest));
  435.     else
  436.     {
  437.         /* source and destination volume must be the same */
  438.         if (source->vRefNum != dest->vRefNum)
  439.             return (paramErr);
  440.         
  441.         pb.ioNamePtr = (StringPtr) &(source->name);
  442.         pb.ioVRefNum = source->vRefNum;
  443.         pb.ioDirID = source->parID;
  444.         pb.ioNewDirID = dest->parID;
  445.         pb.ioNewName = (StringPtr) &(dest->name);
  446.         return (PBCatMoveSync(&pb));
  447.     }
  448. }
  449.  
  450. /*****************************************************************************/
  451.  
  452. /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
  453. /* on the specified volume. Ripped off from Feldman's code. */
  454.  
  455. static    OSErr    GenerateUniqueName(short volume,
  456.                                    long *startSeed,
  457.                                    long dir1,
  458.                                    long dir2,
  459.                                    StringPtr uniqueName)
  460. {
  461.     OSErr            error = noErr;
  462.     long            i;
  463.     CInfoPBRec        cinfo;
  464.     
  465.     cinfo.hFileInfo.ioVRefNum = volume;
  466.     cinfo.hFileInfo.ioFDirIndex = 0;
  467.     cinfo.hFileInfo.ioNamePtr = uniqueName;
  468.  
  469.     while (error != fnfErr) {
  470.         (*startSeed)++;        
  471.         cinfo.hFileInfo.ioNamePtr[0] = 8;
  472.         for (i = 1; i <= 8; i++)
  473.             cinfo.hFileInfo.ioNamePtr[i] = "0123456789ABCDEF"[((*startSeed >> ((8-i)*4)) & 0xf)];
  474.         cinfo.hFileInfo.ioDirID = dir1;
  475.         error = fnfErr;
  476.         for (i = 1; i <= 2; i++) {
  477.             error = error & PBGetCatInfoSync(&cinfo);
  478.             cinfo.hFileInfo.ioDirID = dir2;
  479.             if ((error != fnfErr) && (error != noErr))
  480.                 return (error);
  481.         }
  482.     }
  483.     return (noErr);
  484. }
  485.  
  486. /*****************************************************************************/
  487.  
  488. pascal    OSErr    FSpExchangeFilesCompat(const FSSpec *source,
  489.                                        const FSSpec *dest)
  490. {
  491.     HParamBlockRec            pb;
  492.     CInfoPBRec                catInfoSource, catInfoDest;
  493.     OSErr                    error, error2;
  494.     Str31                    unique1, unique2;
  495.     StringPtr                unique1Ptr, unique2Ptr, swapola;
  496.     GetVolParmsInfoBuffer    volInfo;
  497.     long                    theSeed, temp;
  498.     
  499.     if (FSHasFSSpecCalls() && HasFSpExchangeFilesCompatibilityFix())
  500.         return (FSpExchangeFiles(source, dest));
  501.     else
  502.     {
  503.         /* Make sure the source and destination are on the same volume */
  504.         if (source->vRefNum != dest->vRefNum)
  505.             return (paramErr);
  506.         
  507.         /* Try PBExchangeFiles first since it preserves the file ID reference */
  508.         pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
  509.         pb.fidParam.ioVRefNum = source->vRefNum;
  510.         pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
  511.         pb.fidParam.ioDestDirID = dest->parID;
  512.         pb.fidParam.ioSrcDirID = source->parID;
  513.     
  514.         error = PBExchangeFilesSync(&pb);
  515.     
  516.         /* Note: The compatibility case won't work for files with *Btree control blocks. */
  517.         /* Right now the only *Btree files are created by the system. */
  518.         if (error != noErr)
  519.         {
  520.             pb.ioParam.ioNamePtr = nil;
  521.             pb.ioParam.ioBuffer = (Ptr) &volInfo;
  522.             pb.ioParam.ioReqCount = sizeof(volInfo);
  523.             error2 = PBHGetVolParmsSync(&pb);
  524.             
  525.             /* continue if volume has no fileID support (or no GetVolParms support) */
  526.             if ((error2 == noErr) && (volInfo.vMAttrib & (1<<bHasFileIDs)))
  527.                 return (error);
  528.     
  529.             /* Get the catalog information for each file */
  530.             /* and make sure both files are *really* files */
  531.             catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
  532.             catInfoSource.hFileInfo.ioFDirIndex = 0;
  533.             catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
  534.             catInfoSource.hFileInfo.ioDirID = source->parID;
  535.             catInfoSource.hFileInfo.filler2 = 0;
  536.             error = PBGetCatInfoSync(&catInfoSource);
  537.             if (error != noErr)
  538.                 return (error);
  539.             if (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask)
  540.                 return (notAFileErr);
  541.             
  542.             catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
  543.             catInfoDest.hFileInfo.ioFDirIndex = 0;
  544.             catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
  545.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  546.             catInfoDest.hFileInfo.filler2 = 0;
  547.             error = PBGetCatInfoSync(&catInfoDest);
  548.             if (error != noErr)
  549.                 return (error);
  550.             if (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask)
  551.                 return (notAFileErr);
  552.             
  553.             /* generate 2 filenames that are unique in both directories */
  554.             theSeed = 0x64666A6C;    /* a fine unlikely filename */
  555.             unique1Ptr = (StringPtr)&unique1;
  556.             unique2Ptr = (StringPtr)&unique2;
  557.             
  558.             error = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
  559.             if (error != noErr)
  560.                 return (error);
  561.     
  562.             GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
  563.             if (error != noErr)
  564.                 return (error);
  565.     
  566.             /* rename source to unique1 */
  567.             pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
  568.             pb.ioParam.ioMisc = (Ptr) unique1Ptr;
  569.             error = PBHRenameSync(&pb);
  570.             if (error != noErr)
  571.                 return (error);        
  572.             
  573.             /* rename dest to unique2 */
  574.             pb.ioParam.ioMisc = (Ptr) unique2Ptr;
  575.             pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
  576.             pb.fileParam.ioDirID = dest->parID;
  577.             error = PBHRenameSync(&pb);
  578.             if (error != noErr)
  579.                 goto error2;    /* back out gracefully by renaming unique1 back to source */
  580.                 
  581.             /* If files are not in same directory, swap their locations */
  582.             if (source->parID != dest->parID)
  583.             {
  584.                 /* move source file to dest directory */
  585.                 pb.copyParam.ioNamePtr = unique1Ptr;
  586.                 pb.copyParam.ioNewName = nil;
  587.                 pb.copyParam.ioNewDirID = dest->parID;
  588.                 pb.copyParam.ioDirID = source->parID;
  589.                 error = PBCatMoveSync((CMovePBPtr) &pb);
  590.                 if (error != noErr)
  591.                     goto error1;    /* back out gracefully by renaming both files to original names */
  592.                 
  593.                 /* move dest file to source directory */
  594.                 pb.copyParam.ioNamePtr = unique2Ptr;
  595.                 pb.copyParam.ioNewDirID = source->parID;
  596.                 pb.copyParam.ioDirID = dest->parID;
  597.                 error = PBCatMoveSync((CMovePBPtr) &pb);
  598.                 if (error != noErr)
  599.                 {
  600.                     /* life is very bad.  We'll at least try to move source back */
  601.                     pb.copyParam.ioNamePtr = unique1Ptr;
  602.                     pb.copyParam.ioNewName = nil;
  603.                     pb.copyParam.ioNewDirID = source->parID;
  604.                     pb.copyParam.ioDirID = dest->parID;
  605.                     (void) PBCatMoveSync((CMovePBPtr) &pb);    /* ignore errors */
  606.                     goto error1;    /* back out gracefully by renaming both files to original names */
  607.                 }
  608.             }
  609.             
  610.             /* Make unique1Ptr point to file in source->parID */
  611.             /* and unique2Ptr point to file in dest->parID */
  612.             /* This lets us fall through to the rename code below */
  613.             swapola = unique1Ptr;
  614.             unique1Ptr = unique2Ptr;
  615.             unique2Ptr = swapola;
  616.     
  617.             /* At this point, the files are in their new locations (if they were moved) */
  618.             /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
  619.             /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
  620.             /* Need to swap attributes except mod date and swap names */
  621.     
  622.             /* swap the catalog info by re-aiming the CInfoPB's */
  623.             catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
  624.             catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
  625.             
  626.             catInfoSource.hFileInfo.ioDirID = source->parID;
  627.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  628.             
  629.             /* Swap the original mod dates with each file */
  630.             temp = catInfoSource.hFileInfo.ioFlMdDat;
  631.             catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
  632.             catInfoDest.hFileInfo.ioFlMdDat = temp;
  633.             
  634.             /* Here's the swap (ignore errors) */
  635.             (void) PBSetCatInfoSync(&catInfoSource); 
  636.             (void) PBSetCatInfoSync(&catInfoDest);
  637.             
  638.             /* rename unique2 back to dest */
  639. error1:
  640.             pb.ioParam.ioMisc = (Ptr) &(dest->name);
  641.             pb.fileParam.ioNamePtr = unique2Ptr;
  642.             pb.fileParam.ioDirID = dest->parID;
  643.             (void) PBHRenameSync(&pb);    /* ignore errors */
  644.     
  645.             /* rename unique1 back to source */
  646. error2:
  647.             pb.ioParam.ioMisc = (Ptr) &(source->name);
  648.             pb.fileParam.ioNamePtr = unique1Ptr;
  649.             pb.fileParam.ioDirID = source->parID;
  650.             (void) PBHRenameSync(&pb); /* ignore errors */
  651.         }
  652.         return (error);
  653.     }
  654. }
  655.  
  656. /*****************************************************************************/
  657.  
  658. /* 
  659. **    Resource Manager FSp calls
  660. */
  661.  
  662. /*****************************************************************************/
  663.  
  664. pascal    short    FSpOpenResFileCompat(const FSSpec *spec,
  665.                                      SignedByte permission)
  666. {
  667.     /* ••••• NEED TO MAKE SURE QUICKTIME PROVIDES THIS ONE ••••• */
  668.     if (FSHasFSSpecCalls() || QTHasFSSpecCalls())
  669.         return (FSpOpenResFile(spec, permission));
  670.     else
  671.         return (HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission));
  672. }
  673.  
  674. /*****************************************************************************/
  675.  
  676. pascal    void    FSpCreateResFileCompat(const FSSpec *spec,
  677.                                        OSType creator,
  678.                                        OSType fileType,
  679.                                        ScriptCode scriptTag)
  680. {
  681.     OSErr            result;
  682.     CInfoPBRec        pb;
  683.     
  684.     /* ••••• NEED TO MAKE SURE QUICKTIME PROVIDES THIS ONE ••••• */
  685.     if ((FSHasFSSpecCalls() || QTHasFSSpecCalls()) && HasFSpCreateScriptSupportFix())
  686.     {
  687.         FSpCreateResFile(spec, creator, fileType, scriptTag);
  688.         return;
  689.     }
  690.     else
  691.     {
  692.         HCreateResFile(spec->vRefNum, spec->parID, spec->name);
  693.         if (ResError() == noErr)
  694.         {
  695.             /* get info on created item */
  696.             pb.hFileInfo.ioVRefNum = spec->vRefNum;
  697.             pb.hFileInfo.ioDirID = spec->parID;
  698.             pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
  699.             pb.hFileInfo.ioFDirIndex = 0;
  700.             result = PBGetCatInfoSync(&pb);
  701.             if (result == noErr)
  702.             {
  703.                 /* Set fdScript in FXInfo */
  704.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  705.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  706.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  707.                 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  708.                                                         ((char)scriptTag | (char)0x80) :
  709.                                                         (smRoman);
  710.                 /* Set creator/fileType */
  711.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  712.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  713.                 
  714.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  715.                 pb.hFileInfo.ioDirID = spec->parID;
  716.                 result = PBSetCatInfoSync(&pb);
  717.             }
  718.             /* Set ResErr low memory global to result */
  719.             LMSetResErr(result);
  720.         }
  721.         return;
  722.     }
  723. }
  724.  
  725. /*****************************************************************************/
  726.